#include "widget.h"

#include <QLabel>
#include <QGridLayout>
#include <QPushButton>
#include <QFile>
#include <QDBusInterface>
#include <QDBusPendingReply>
#include <QDBusUnixFileDescriptor>
#include <QFutureWatcher>
#include <QtConcurrentRun>
#include <QApplication>
#include <QDesktopWidget>

#include <QDebug>

#include <sys/shm.h>
#include <fcntl.h>
#include <unistd.h>

static int readData(int fd, QByteArray &data)
{
    // implementation based on QtWayland file qwaylanddataoffer.cpp
    char buf[4096];
    int retryCount = 0;
    int n;
    while (true) {
        n = read(fd, buf, sizeof buf);
        // give user 30 sec to click a window, afterwards considered as error
        if (n == -1 && (errno == EAGAIN) && ++retryCount < 30000) {
            usleep(1000);
        } else {
            break;
        }
    }
    if (n > 0) {
        data.append(buf, n);
        n = readData(fd, data);
    }
    return n;
}

static QImage readImage(int pipeFd)
{
    QByteArray content;
    if (readData(pipeFd, content) != 0) {
        close(pipeFd);
        return QImage();
    }
    close(pipeFd);
    QDataStream ds(content);
    QImage image;
    ds >> image;
    return image;
}

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    QGridLayout *layout = new QGridLayout(this);

    QPushButton *button = new QPushButton("截图", this);
    layout->addWidget(button, 0, 0);
    connect(button, &QPushButton::clicked, this, &Widget::onButtonClicked);

    setLayout(layout);
    setFixedSize(400, 300);
}

void Widget::onButtonClicked()
{
    // Create a pipe to receive the file descriptor
    int fd[2];
    if (pipe2(fd, O_CLOEXEC|O_NONBLOCK) != 0) {
        qWarning() << "pipe2 failed";
        return;
    }

    auto screenNumber = QApplication::desktop()->screenNumber();
    // Call the DBus method to take a screenshot
    QDBusInterface *interface = new QDBusInterface("org.ukui.KWin", "/Screenshot", "org.ukui.kwin.Screenshot");

    // The screenshot will be written to the pipe
    // args: fd, includeCursor, screenNumber
    QDBusPendingReply reply = interface->asyncCall("screenshotFullscreen", QVariant::fromValue(QDBusUnixFileDescriptor(fd[1])), false, screenNumber);

    QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
    QObject::connect(watcher, &QFutureWatcher<QImage>::finished, this,
        [watcher, this] {
            watcher->deleteLater();
            const QImage img = watcher->result();

            // Save the image to a file
            qDebug() << "Got image" << img.size();
            img.save("screenshot.png");
        }
    );
    watcher->setFuture(QtConcurrent::run(readImage, fd[0]));

    ::close(fd[1]);
}